#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <time.h>
#include "TADComunicacion.h"

int32_t Comunicacion(int32_t, char, char[100], char[1100]);
char *obtenerPuertoConsola();
int32_t obtenerCadena(char *, char[100], int32_t);

char PORT[256];
char archConfig[256];

int32_t main(int32_t argv, char *argc[]) {


	char msjConsola[100], comandoConsola[100], respuesta[1100], numero[200];
	int32_t sockUnix, len, resultado=0, i,var=1,num1 = -1, num2 = -1, j = 0,cantMensajes = 0, flagSalida = 1, bytesRec = -1, flagT = 0;
	struct sockaddr_un address;
	char opcion[5];
	TMensaje *msjRespuesta;

	int32_t max_tries = 0;

	memset(archConfig,'\0',sizeof(archConfig));
	memcpy(archConfig,argc[1],strlen(argc[1]));

	obtenerPuertoConsola();
	memset(opcion, '\0', 5);

	sockUnix = socket(AF_UNIX, SOCK_STREAM, 0);
	address.sun_family = AF_UNIX;
	strcpy(address.sun_path, PORT);
	len = sizeof(address);
	resultado = connect(sockUnix, (struct sockaddr*) &address, len);

	while (resultado < 0) {
		if (max_tries == 5) {
			break;
		}
		sleep(3);
		printf("Try n#%d\n", max_tries++);
		resultado = connect(sockUnix, (struct sockaddr*) &address, len);
	}

	if (max_tries == 5) {
		perror("No se pudo iniciar la consola.\n");
		exit(EXIT_FAILURE);
	}

	printf(" ----------------------------------------------------------------------------\n");
	printf("|                            Consola del PPD                                     |\n");
	printf(" ----------------------------------------------------------------------------\n\n\n");

	while(flagSalida){
		i = 0;
		fflush(stdin);
		memset(msjConsola, '\0', 100);
		memset(comandoConsola, '\0', 100);
		printf("\n--Ingrese el comando a enviar:");
		fgets(msjConsola, 100, stdin);

		msjConsola[strlen(msjConsola) - 1] = '\0';
		while ((msjConsola[i] != ' ') && (msjConsola[i] != '\0')) {
			comandoConsola[i] = msjConsola[i];
			i++;
		}
		i++;

		if ((!strcmp(opcion, "1")) || (!strcmp(opcion, "2"))|| (!strcmp(msjConsola, "info"))|| (!strcmp(msjConsola, "exit"))|| (!strcmp(comandoConsola, "clean"))|| (!strcmp(comandoConsola, "trace"))|| (!strcmp(msjConsola, "clear"))) {
			if (!strcmp(msjConsola, "clear")) {
				system("clear");
				printf(" ----------------------------------------------------------------------------\n");
				printf("|                            Consola del PPD                                     |\n");
				printf(" ----------------------------------------------------------------------------\n\n\n");

			}
			if ((!strcmp(msjConsola, "info")) || (!strcmp(msjConsola, "exit"))|| (!strcmp(comandoConsola, "clean"))|| (!strcmp(comandoConsola, "trace"))) {

				if (!strcmp(comandoConsola, "clean")) {
					if (msjConsola[i] == '\0') {
						printf("\nMensaje invalido.\n");
					}
					else{
						memset(numero, '\0', 200);
						j = 0;
						while ((msjConsola[i] != ' ') && (msjConsola[i] != '\0')) {
							numero[j] = msjConsola[i];
							i++;
							j++;
						}
						i++;
						j = 0;
						num1 = atoi(numero);
						memset(numero, '\0', 200);
						while ((msjConsola[i] != ' ') && (msjConsola[i] != '\0')) {
							numero[j] = msjConsola[i];
							i++;
							j++;
						}
						num2 = atoi(numero);
						if (num2 < num1)
							printf("\nSectores invalidos.\n");
						else {
							var=Comunicacion(sockUnix, 'X', msjConsola, respuesta);
							if(var==0)
								flagSalida=0;
							else
								printf("Respuesta recibida:%s\n", respuesta);
						}
					}
				}
				else {
					if (!strcmp(comandoConsola, "trace")) {
						if (msjConsola[i] == '\0')
							printf("Mensaje invalido.\n");
						else {
							ComunicacionA(sockUnix, 'X', msjConsola);
							msjRespuesta = (TMensaje *) calloc(1,sizeof(TMensaje));
							flagT = 0;
							bytesRec = -1;
							while (bytesRec < 10) {
								bytesRec = recv(sockUnix, (void*) msjRespuesta,sizeof(struct TMensaje), MSG_WAITALL);
								if(bytesRec==0){
									flagSalida=0;
									break;
								}
							}
							cantMensajes = 0;
							cantMensajes = atoi(msjRespuesta->payload);
							bytesRec = -1;
							while (bytesRec < 0) {
								bytesRec = recv(sockUnix, (void*) msjRespuesta,sizeof(struct TMensaje), MSG_WAITALL);
								if(bytesRec==0){
									flagSalida=0;
									break;
								}
							}
							flagT = 0;
							while (flagT < cantMensajes) {
								if (flagT == 0) {
									printf("Respuesta recibida del comando:%s",msjRespuesta->payload);
									flagT++;
								}
								else {
									printf("%s", msjRespuesta->payload);
									flagT++;
								}
								if (flagT != cantMensajes) {
									bytesRec = -1;
									while (bytesRec < 0) {
										bytesRec = recv(sockUnix,(void*) msjRespuesta,sizeof(struct TMensaje),MSG_WAITALL);
										if(bytesRec==0){
											flagSalida=0;
											break;
										}
									}
								}
								else{
									break;
								}
							}
							free(msjRespuesta);
							flagT = 0;
						}
					}
					else {
						if (!strcmp(comandoConsola, "exit")){
							flagSalida = 0;
						}
						else{
							var=Comunicacion(sockUnix, 'X', msjConsola, respuesta);
							if(var==0)
								flagSalida=0;
							else
								printf("Respuesta recibida:%s\n\n", respuesta);
						}

					}
				}
			}
		}
		else {
			printf("\nMensaje incorrecto.\n");
		}
	}
	printf("\n##Consola Cerrada correctamente.\n");

	exit(EXIT_SUCCESS);
	//return 1;
}

/******* Archivo de Configuracion *******/
int32_t obtenerCadena(char *archivo, char readBuffer[100], int32_t linea) {
	FILE *f1;
	int32_t i = 1;

	f1 = fopen(archivo, "rb");
	if (f1 == NULL) {
		printf("\nNo se puede abrir el archivo de Configuracion de Disco\n");
		return -1;
	} else {
		while (i <= linea) {
			fgets(readBuffer, 100, f1);
			i++;
		}
		return 0;
	}
}

char *obtenerPuertoConsola() {

	int32_t pos = 0, j = 0;
	extern char PORT[256];
	char ReadBuffer[100];

	if (obtenerCadena(archConfig, ReadBuffer, 5) != -1) {

		while (ReadBuffer[j] != ':')
			j++;

		j++;
		while ((ReadBuffer[j] != '\n') && (ReadBuffer[j] != '\r')) {
			PORT[pos] = ReadBuffer[j];
			j++;
			pos++;
		}
		PORT[pos] = '\0';
		return PORT;
	} else
		return ("Error");
}

//FUNCION QUE ENVIA UN MENSAJE NIPC EXTENDIDO ESPERANDO RESPUESTA
int32_t Comunicacion(int32_t sock, char desc, char cadena[100],
		char respuesta[1100]) {
	TMensaje *Mensaje, *OtroMensaje;
	time_t tActual;
	struct tm* tiempoGenerico;
	char cad[50];
	int32_t bytesRec = -1;

	tActual = time(NULL);
	tiempoGenerico = (struct tm*) localtime(&tActual);
	strftime(cad, 50, "%H%M%S", tiempoGenerico);

	Mensaje = (TMensaje*) calloc(1, sizeof(TMensaje));

	sprintf(Mensaje->idDescriptor, "%s%010i", cad, rand());
	Mensaje->payloadDescriptor = desc;
	Mensaje->payloadLength = (int32_t) strlen(cadena);
	strcpy(Mensaje->payload, cadena);
	send(sock, (void*) Mensaje, sizeof(TMensaje), 0);

	//printf("Envie:%s\n",Mensaje->payload);
	free(Mensaje);

	OtroMensaje = (TMensaje*) calloc(1, sizeof(TMensaje));
	//memset(OtroMensaje->payload,'\0',1100);
	while (bytesRec < 200) {
		bytesRec = recv(sock, (void*) OtroMensaje, sizeof(struct TMensaje), 0); // RECIBO RESPUESTA
		if(bytesRec==0){
			return 0;
		}
	}

	strcpy(respuesta, OtroMensaje->payload);
	free(OtroMensaje);
	return 1;
}
